package org.jsola.hr.service.impl;

import com.google.common.collect.Lists;
import org.jsola.common.PageKit;
import org.jsola.contract.entity.ContractDO;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IDepInfoDAO;
import org.jsola.hr.dto.CompanyUpdateDTO;
import org.jsola.hr.dto.DepInfoAddDTO;
import org.jsola.hr.dto.DepInfoUpdateDTO;
import org.jsola.hr.entity.CompanyDO;
import org.jsola.hr.entity.DepInfoDO;
import org.jsola.hr.provider.IContractProviderService;
import org.jsola.hr.query.DepAndInfoQuery;
import org.jsola.hr.query.DepInfoQuery;
import org.jsola.hr.query.EmpDepQuery;
import org.jsola.hr.query.EmpReduceQuery;
import org.jsola.hr.service.ICompanyService;
import org.jsola.hr.service.IDepInfoService;
import org.jsola.hr.service.IEmpDepService;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.vo.DepInfoListVO;
import org.jsola.hr.vo.DepInfoVO;
import org.jsola.hr.vo.EmpInfoListVO;
import org.jsola.hr.vo.EmpReduceInfoVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrDepInfoServiceImpl")
public class DepInfoServiceImpl implements IDepInfoService {

    @Autowired
    private IDepInfoDAO depInfoDAO;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private ICompanyService companyService;
    @Autowired
    private IContractProviderService contractProviderService;

    @Lazy
    @Autowired
    private IEmpDepService empDepService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public DepInfoVO save(DepInfoAddDTO depInfoAddDTO, TokenUser tokenUser) {
        // 校验父部门
        checkParentDep(depInfoAddDTO.getParentId(), depInfoAddDTO.getCompanyId(), tokenUser.getSiteId());
        // 校验部门编码
        checkDepCode("", depInfoAddDTO.getCode(), depInfoAddDTO.getCompanyId(), tokenUser.getSiteId());
        //校验部门名称是否存在
        checkDepName(depInfoAddDTO.getName()
                , depInfoAddDTO.getParentId()
                , depInfoAddDTO.getCompanyId()
                , tokenUser.getSiteId());
        // 转DO
        DepInfoDO depInfoDO = depInfoAddDTO.to(DepInfoDO.class);

        // 保存
        depInfoDO = save(depInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());

        return depInfoDO.to(DepInfoVO.class);
    }

    /**
     * 校验部门code是否存在
     *
     * @param code      部门code
     * @param companyId 公司id
     * @param siteId    站点id
     */
    private void checkDepCode(String id, String code, String companyId, String siteId) {
        if (StringUtils.isEmpty(code)) {
            return;
        }
        DepInfoVO depInfoDO = selectByCode(code, siteId, companyId);
        if (!Objects.isNull(depInfoDO)) {
            if (StringUtils.isEmpty(id) || !id.equals(depInfoDO.getId())) {
                throw new ParamException("部门编码'" + code + "'已存在");
            }
        }
    }

    /**
     * 校验部门名称是否重复
     *
     * @param depName   部门名称
     * @param parentId  父Id
     * @param companyId 公司id
     * @param siteId    站点id
     */
    private void checkDepName(String depName, String parentId, String companyId, String siteId) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("name", depName)
                .andEqualTo("parentId", parentId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId);
        DepInfoDO depInfoDO = depInfoDAO.selectOneByExample(example);
        if (Objects.nonNull(depInfoDO)) {
            throw new ParamException("该用工单位下已有名称为" + depName + "的部门");
        }
    }

    /**
     * 校验父部门
     *
     * @param parentId  父部门id
     * @param companyId 公司id
     * @param siteId    站点id
     */
    private void checkParentDep(String parentId, String companyId, String siteId) {
        if ("0".equals(parentId)) {
            return;
        }
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("id", parentId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId);
        DepInfoDO depInfoDO = depInfoDAO.selectOneByExample(example);
        if (Objects.isNull(depInfoDO)) {
            // 校验父部门是不是站点级部门
            DepInfoVO depInfoSite = selectByCode(siteId, siteId, null);
            if (Objects.nonNull(depInfoSite) && parentId.equals(depInfoSite.getId())) {
                // 父部门是站点级
                return;
            }
            throw new ParamException("父部门不存在或已删除,请检查");
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(DepInfoUpdateDTO depInfoUpdateDTO, TokenUser tokenUser) {
        //转DO
        DepInfoDO depInfoDO = depInfoUpdateDTO.to(DepInfoDO.class);
        //查询是否存在当前编码
        checkDepCode(depInfoDO.getId(), depInfoDO.getCode(), depInfoDO.getCompanyId(), tokenUser.getSiteId());
        // 校验父部门
        checkParentDep(depInfoDO.getParentId(), depInfoDO.getCompanyId(), tokenUser.getSiteId());

        // 校验id不能与parentId一致
        if (depInfoDO.getParentId().equals(depInfoDO.getId())) {
            throw new ParamException("数据的父id不能为本身");
        }

        //根据主键更新，只更新非null值
        int upCount = updateByIdSelective(depInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());

        if (!StringUtils.isEmpty(depInfoUpdateDTO.getName())) {
            // 公司级部门
            DepInfoVO depInfoCompany = selectByCode(depInfoDO.getCompanyId(), tokenUser.getSiteId(), depInfoDO.getCompanyId());
            // 公司级部门修改
            if (Objects.nonNull(depInfoCompany) && depInfoCompany.getId().equals(depInfoDO.getId())) {
                DepInfoDO depInfoNew = selectDOById(depInfoDO.getId(), tokenUser.getSiteId());
                CompanyDO companyDO = companyService.selectDOById(depInfoDO.getCompanyId(), tokenUser.getSiteId());
                if (!depInfoNew.getName().equals(companyDO.getName())) {
                    //  修改公司名称
                    CompanyUpdateDTO companyUpdateDTO = new CompanyUpdateDTO();
                    companyUpdateDTO.setId(companyDO.getId());
                    companyUpdateDTO.setName(depInfoNew.getName());

                    companyService.update(companyUpdateDTO, tokenUser);
                }
            }
        }

        return upCount;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... depInfoIds) {

        if (depInfoIds == null || depInfoIds.length == 0) {
            return 0;
        }
        // 获取当前部门和下级部门
        List<DepInfoDO> allDepList = listAllAndChild(tokenUser.getSiteId(), depInfoIds);
        for (DepInfoDO depInfo : allDepList) {
            DepInfoDO depDO = selectDOById(depInfo.getId(), tokenUser.getSiteId());
            if (Objects.isNull(depDO)) {
                continue;
            }
            List<EmpInfoListVO> empInfoList = empInfoService.listAllVoByDepId(depDO.getCompanyId(), "", false, true, tokenUser, depInfo.getId());
            if (!CollectionUtils.isEmpty(empInfoList)) {
                throw new ParamException("部门或部门的子部门内'" + depInfo.getName() + "'内还存在员工,请先处理");
            }
        }
        // 将部门及子部门一起删除
        String[] ids = allDepList.stream().map(DepInfoDO::getId).toArray(String[]::new);

        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) ids);
    }


    @Override
    public DepInfoVO selectById(String depInfoId, String siteId) {
        DepInfoDO depInfoDO = selectDOById(depInfoId, siteId);
        if (depInfoDO == null) {
            return null;
        }
        return depInfoDO.to(DepInfoVO.class);
    }

    @Override
    public DepInfoDO selectById(String depInfoId, TokenUser tokenUser) {
        String siteId = tokenUser.getSiteId();
        return listById(depInfoId, siteId);
    }

    @Override
    public DepInfoVO selectByIdWhetherDel(String depInfoId, String siteId) {
        if (depInfoId == null) {
            return null;
        }
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("id", depInfoId);
        DepInfoDO depInfoDO = depInfoDAO.selectOneByExample(example);
        if (depInfoDO != null) {
            return depInfoDO.to(DepInfoVO.class);
        }
        return null;
    }

    @Override
    public List<DepInfoListVO> select(DepInfoQuery depInfoQuery, String siteId) {
        List<DepInfoListVO> depInfoList = getVoListByDoList(selectDO(depInfoQuery, siteId));
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new ArrayList<>();
        }
        depInfoList.forEach(depInfoListVO -> {
            DepInfoDO depInfoDO = selectDOById(depInfoListVO.getParentId(), siteId);
            if (!ObjectUtils.isEmpty(depInfoDO) && depInfoDO.getSiteId().equals(depInfoDO.getCode())) {
                depInfoListVO.setIsTop(true);
            }
        });
        return depInfoList;
    }

    /**
     * 根据doList获取voList
     *
     * @param doList doList
     * @return voList
     */
    private List<DepInfoListVO> getVoListByDoList(List<DepInfoDO> doList) {
        if (CollectionUtils.isEmpty(doList)) {
            return doList == null ? null : new ArrayList<>();
        }
        return doList.stream()
                .map(depInfoDO -> depInfoDO.to(DepInfoListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(DepInfoQuery depInfoQuery, String siteId) {
        Example example = buildExample(depInfoQuery, siteId);
        return depInfoDAO.selectCountByExample(example);
    }

    @Override
    public Page<DepInfoListVO> selectPage(DepInfoQuery depInfoQuery, String siteId) {
        Example example = buildExample(depInfoQuery, siteId);
        Page<DepInfoDO> page = depInfoDAO.selectPageByExample(example,
                depInfoQuery.getPageNo(),
                depInfoQuery.getPageSize());

        return page.to(DepInfoListVO.class);
    }

    @Override
    public DepInfoDO selectDOById(String depInfoId, String siteId) {
        return listById(depInfoId, siteId);
    }

    @Override
    public List<DepInfoDO> selectDO(DepInfoQuery depInfoQuery, String siteId) {
        Example example = buildExample(depInfoQuery, siteId);
        return depInfoDAO.selectByExample(example);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param depInfoQuery 查询参数
     * @param siteId       所属站点id
     * @return example
     */
    private Example buildExample(DepInfoQuery depInfoQuery, String siteId) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (depInfoQuery.getName() != null) {
            example.and().andLike("name", "%" + depInfoQuery.getName() + "%");
        }
        if (depInfoQuery.getCode() != null) {
            example.and().andLike("code", "%" + depInfoQuery.getCode() + "%");
        }
        if (depInfoQuery.getType() != null) {
            example.and().andEqualTo("type", depInfoQuery.getType());
        }
        if (depInfoQuery.getVirural() != null) {
            example.and().andEqualTo("virural", depInfoQuery.getVirural());
        }
        if (depInfoQuery.getLeader() != null) {
            example.and().andLike("leader", "%" + depInfoQuery.getLeader() + "%");
        }
        if (depInfoQuery.getAddressId() != null) {
            example.and().andEqualTo("addressId", depInfoQuery.getAddressId());
        }
        if (depInfoQuery.getAddress() != null) {
            example.and().andLike("address", "%" + depInfoQuery.getAddress() + "%");
        }
        if (depInfoQuery.getDesc() != null) {
            example.and().andLike("desc", "%" + depInfoQuery.getDesc() + "%");
        }
        if (depInfoQuery.getFormalNum() != null) {
            example.and().andEqualTo("formalNum", depInfoQuery.getFormalNum());
        }
        if (depInfoQuery.getInformalNum() != null) {
            example.and().andEqualTo("informalNum", depInfoQuery.getInformalNum());
        }
        if (depInfoQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", depInfoQuery.getCompanyId());
        }
        if (depInfoQuery.getLevel() != null) {
            example.and().andEqualTo("level", depInfoQuery.getLevel());
        }
        if (depInfoQuery.getSort() != null) {
            example.and().andEqualTo("sort", depInfoQuery.getSort());
        }
        if (depInfoQuery.getParentId() != null) {
            example.and().andEqualTo("parentId", depInfoQuery.getParentId());
        }
        if (depInfoQuery.getGmtCreateStart() != null &&
                depInfoQuery.getGmtCreateEnd() != null) {
            example.and().andBetween("gmtCreate", depInfoQuery.getGmtCreateStart(),
                    depInfoQuery.getGmtCreateEnd());
        }
        if (depInfoQuery.getCreateUserId() != null) {
            example.and().andLike("createUserId", "%" + depInfoQuery.getCreateUserId() + "%");
        }
        if (depInfoQuery.getGmtModifiedStart() != null &&
                depInfoQuery.getGmtModifiedEnd() != null) {
            example.and().andBetween("gmtModified", depInfoQuery.getGmtModifiedStart(),
                    depInfoQuery.getGmtModifiedEnd());
        }
        if (depInfoQuery.getModifiedUserId() != null) {
            example.and().andLike("modifiedUserId", "%" + depInfoQuery.getModifiedUserId() + "%");
        }
        example.orderBy("gmtCreate").desc();
//        // 排序
//        ExampleKit.setExampleOrder(example,depInfoQuery.getOrders());
        return example;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<DepInfoListVO> listTree(DepInfoQuery depInfoQuery, String siteId) {
        String companyId = depInfoQuery.getCompanyId();
        ParamException.hasLength(companyId, "请传递公司id");

        // 有公司,查询公司的,获取一级,一级是用siteId做的code
        DepInfoVO depInfoSite = selectByCode(siteId, siteId, null);
        String parentId = depInfoSite.getId();

        // 获取公司部门树,根据父部门id
        return listCompanyDepByParent(companyId, parentId, true, siteId);
    }

    /**
     * 获取公司部门树,根据父部门id
     *
     * @param companyId 公司id
     * @param parentId  父部门id
     * @param isTree    是否树形返回
     * @param siteId    站点id
     * @return 当前部门下公司部门树
     */
    private List<DepInfoListVO> listCompanyDepByParent(String companyId, String parentId, Boolean isTree, String siteId) {
        if (StringUtils.isEmpty(companyId)) {
            return new ArrayList<>();
        }
        if (StringUtils.isEmpty(parentId)) {
            return new ArrayList<>();
        }
        // 公司下所有部门
        List<DepInfoListVO> depInfoList = getVoListByDoList(listByCompanyId(companyId, siteId));
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new ArrayList<>();
        }
        // 根据父级分组
        Map<String, List<DepInfoListVO>> parentDepMap = depInfoList.stream()
                .collect(Collectors.groupingBy(DepInfoListVO::getParentId));

        return listChildDepByParent(parentDepMap, parentId, isTree);
    }

    /**
     * 获取部门的子部门
     *
     * @param parentDepMap 父子部门map,<parentId,子部门集合>
     * @param parentId     父id
     * @param isTree       是否树形返回
     * @return 部门的子部门
     */
    private List<DepInfoListVO> listChildDepByParent(Map<String, List<DepInfoListVO>> parentDepMap, String parentId, Boolean isTree) {
        // 部门id是否有子部门
        if (parentDepMap.containsKey(parentId)) {
            // 所有的部门及子部门
            // 当前部门的子部门
            List<DepInfoListVO> depInfoList = parentDepMap.get(parentId);

            if (!CollectionUtils.isEmpty(depInfoList)) {
                // 增加到全部中
                List<DepInfoListVO> allDepInfoList = new ArrayList<>(depInfoList);

                depInfoList.parallelStream().forEach(
                        depInfo -> {
                            // 迭代获取子部门的子集
                            List<DepInfoListVO> childDepInfoList = listChildDepByParent(parentDepMap, depInfo.getId(), isTree);
                            if (isTree) {
                                // 树形返回
                                if (CollectionUtils.isEmpty(childDepInfoList)) {
                                    // 没有子部门
                                    depInfo.setChildCount(0);
                                    depInfo.setHasChild(false);
                                    depInfo.setDepChildList(childDepInfoList);
                                } else {
                                    // 有子部门
                                    depInfo.setChildCount(childDepInfoList.size());
                                    depInfo.setHasChild(true);
                                    depInfo.setDepChildList(childDepInfoList);
                                }
                            } else {
                                // 非树形,平级显示
                                if (!CollectionUtils.isEmpty(childDepInfoList)) {
                                    // 增加子部门的子集到全部
                                    allDepInfoList.addAll(childDepInfoList);
                                }
                            }
                        }
                );
                if (isTree) {
                    // 树形
                    return depInfoList;
                } else {
                    // 非树形,平级显示
                    return allDepInfoList;
                }
            }
        }
        return new ArrayList<>();
    }

    @Override
    public DepInfoVO selectByCode(String code, String siteId, String companyId) {
        if (StringUtils.isEmpty(code)) {
            return null;
        }
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("code", code)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("companyId", companyId);
        DepInfoDO depInfoDO = depInfoDAO.selectOneByExample(example);
        if (Objects.isNull(depInfoDO)) {
            return null;
        }
        return depInfoDO.to(DepInfoVO.class);
    }

    @Override
    public DepInfoDO selectByNameAndLevel(String name, Integer level, String parentId, String companyId, TokenUser tokenUser) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("companyId", companyId)
                .andEqualTo("level", level)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if (name != null) {
            example.and().andEqualTo("name", name);
        }
        if (parentId != null) {
            example.and().andEqualTo("parentId", parentId);
        }
        List<DepInfoDO> depInfoDOList = depInfoDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(depInfoDOList)) {
            return null;
        }
        return depInfoDOList.get(0);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteByCompanyId(String companyId, TokenUser tokenUser) {
        // 逻辑删除
        List<DepInfoDO> list = listByCompanyId(companyId, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        String[] ids = list.stream()
                .map(BaseDO::getId).toArray(String[]::new);
        deleteByIds(tokenUser, ids);
    }

    @Override
    public List<DepInfoDO> listByCompanyId(String companyId, String siteId) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("companyId", companyId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        example.orderBy("gmtCreate").desc();
        // 某公司所有的部门
        List<DepInfoDO> depInfoList = depInfoDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(depInfoList)) {
            depInfoList = new ArrayList<>();
        }
        return depInfoList;
    }

    @Override
    public List<DepInfoListVO> getDepAndEmpInfo(DepAndInfoQuery depAndInfoQuery, TokenUser tokenUser) {
        ParamException.hasLength(depAndInfoQuery.getCompanyId(), "请选择要查询的公司");
        // 所有部门
        List<DepInfoListVO> depInfoList = getVoListByDoList(listByCompanyId(depAndInfoQuery.getCompanyId(), tokenUser.getSiteId()));
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new ArrayList<>();
        }

        // 部门与员工的关系
        EmpReduceQuery empReduceQuery = new EmpReduceQuery(
                depAndInfoQuery.getEmpNameOrPhone(),
                depAndInfoQuery.getOnlyUser(),
                depAndInfoQuery.getIsOnlineOrLeave(),
                true,
                null);
        List<EmpReduceInfoVO> depEmpList = empInfoService.listDepEmpInfoByCondition(empReduceQuery, depAndInfoQuery.getCompanyId(), tokenUser);
        // 部门及部门下员工<depId,员工信息>
        Map<String, List<EmpReduceInfoVO>> depEmpMap = depEmpList.parallelStream().collect(
                Collectors.groupingBy(EmpReduceInfoVO::getDepId));

        // 公司层级部门
        DepInfoVO companyDep = selectByCode(depAndInfoQuery.getCompanyId(), tokenUser.getSiteId(), depAndInfoQuery.getCompanyId());
        ParamException.notNull(companyDep, "当前用工单位下没有公司级部门,请联系管理员");

        // 将员工加到部门中
        depInfoList.parallelStream().forEach(
                depInfo -> {
                    // 公司级部门
                    if (depInfo.getId().equals(companyDep.getId())) {
                        // 公司级部门获取无部门员工
                        List<EmpReduceInfoVO> noDepEmpList = empInfoService.listNoDepEmp(depInfo.getCompanyId(), empReduceQuery, tokenUser);
                        depInfo.setNoDepEmpList(noDepEmpList);
                    } else {
                        // 非公司级部门
                        if (depEmpMap.containsKey(depInfo.getId())) {
                            // 部门直属员工
                            List<EmpReduceInfoVO> empList = depEmpMap.get(depInfo.getId());

                            depInfo.setEmpDirectCount(empList.size());
                            depInfo.setEmpDirectList(empList);
                        } else {
                            depInfo.setEmpDirectCount(0);
                            depInfo.setEmpDirectList(null);
                        }
                    }
                }
        );
        // 部门转换成树形,并把下级部门的员工合并到上级部门
        List<DepInfoListVO> companyDepTreeList = buildCompanyDepTree(depInfoList, companyDep.getId());
        // 根据条件获取部门
        if (!StringUtils.isEmpty(depAndInfoQuery.getCurrentDepId())) {
            // 有当前部门的,先筛选下树
            companyDepTreeList = filterDepTreeByCurrentDep(companyDepTreeList, depAndInfoQuery.getCurrentDepId());
        }
        if (!StringUtils.isEmpty(depAndInfoQuery.getDepName())) {
            // 根据部门名称筛选,并把树拍平了,平级返回
            companyDepTreeList = filterDepTreeByDepName(companyDepTreeList, depAndInfoQuery.getDepName());
            if (!CollectionUtils.isEmpty(companyDepTreeList)) {
                // 按照创建时间排序
                companyDepTreeList.sort((o1, o2) -> o2.getGmtCreate().compareTo(o1.getGmtCreate()));
            }

        }
        return companyDepTreeList;
    }

    /**
     * 根据部门名称筛选,并把树拍平了,平级返回
     *
     * @param companyDepTreeList 公司部门树
     * @param depName            部门名称
     * @return 符合条件的部门列表, 平级显示
     */
    private List<DepInfoListVO> filterDepTreeByDepName(List<DepInfoListVO> companyDepTreeList, String depName) {
        if (CollectionUtils.isEmpty(companyDepTreeList)) {
            return new ArrayList<>();
        }
        if (StringUtils.isEmpty(depName)) {
            return new ArrayList<>();
        }
        // 符合条件的部门树
        List<DepInfoListVO> depList = new ArrayList<>();
        companyDepTreeList.parallelStream().forEach(
                depInfo -> {
                    // 迭代查找子部门是否有符合的
                    if (!CollectionUtils.isEmpty(depInfo.getDepChildList())) {
                        List<DepInfoListVO> childDepList = filterDepTreeByDepName(depInfo.getDepChildList(), depName);
                        if (!CollectionUtils.isEmpty(childDepList)) {
                            depList.addAll(childDepList);
                        }
                    }
                    // 当前部门是否符合
                    if (depInfo.getName().contains(depName)) {
                        // 去除子级
                        DepInfoListVO depInfoList = depInfo.to(DepInfoListVO.class);
                        depInfoList.setHasChild(false);
                        depInfoList.setChildCount(0);
                        depInfoList.setDepChildList(null);
                        depList.add(depInfoList);
                    }
                }
        );
        return depList;
    }

    /**
     * 根据当前部门id筛选公司部门树
     *
     * @param companyDepTreeList 公司部门树
     * @param currentDepId       当前部门id
     * @return 符合条件的部门树
     */
    private List<DepInfoListVO> filterDepTreeByCurrentDep(List<DepInfoListVO> companyDepTreeList, String currentDepId) {
        if (CollectionUtils.isEmpty(companyDepTreeList)) {
            return new ArrayList<>();
        }
        if (StringUtils.isEmpty(currentDepId)) {
            return new ArrayList<>();
        }
        // 当前部门
        DepInfoListVO currentDep = companyDepTreeList.parallelStream()
                .filter(depInfo -> depInfo.getId().equals(currentDepId))
                .findFirst().orElse(null);
        if (Objects.nonNull(currentDep)) {
            // 返回当前部门的子级
            return currentDep.getDepChildList();
        } else {
            // 当前层没有,迭代向下寻找
            for (DepInfoListVO depInfo : companyDepTreeList) {
                if (CollectionUtils.isEmpty(depInfo.getDepChildList())) {
                    // 没有子级,继续循环
                    continue;
                }
                // 循环迭代查找
                List<DepInfoListVO> depTree = filterDepTreeByCurrentDep(depInfo.getDepChildList(), currentDepId);
                if (!CollectionUtils.isEmpty(depTree)) {
                    return depTree;
                }
            }
        }
        return new ArrayList<>();
    }

    /**
     * 构建公司部门树
     *
     * @param allDepList   公司下所有部门
     * @param companyDepId 公司级部门id
     * @return 公司部门树
     */
    private List<DepInfoListVO> buildCompanyDepTree(List<DepInfoListVO> allDepList, String companyDepId) {
        List<DepInfoListVO> companyDepTreelist = new ArrayList<>();
        if (StringUtils.isEmpty(companyDepId)) {
            return companyDepTreelist;
        }
        DepInfoListVO companyDep = allDepList.parallelStream()
                .filter(depInfo -> companyDepId.equals(depInfo.getId()))
                .findFirst().orElse(null);
        if (Objects.isNull(companyDep)) {
            return companyDepTreelist;
        }
        // 公司级部门下面的部门树
        List<DepInfoListVO> depTreeList = buildDepTree(allDepList, companyDepId);
        if (!CollectionUtils.isEmpty(depTreeList)) {
            // 有子部门
            companyDep.setHasChild(true);
            companyDep.setChildCount(depTreeList.size());
            companyDep.setDepChildList(depTreeList);
        }
        companyDepTreelist.add(companyDep);
        return companyDepTreelist;
    }

    /**
     * 将部门组装树形结构,并把下级部门的员工合并到上级部门
     *
     * @param allDepInfoList 所有部门列表
     * @param parentId       父部门id
     * @return 部门树形结构
     */
    private List<DepInfoListVO> buildDepTree(List<DepInfoListVO> allDepInfoList, String parentId) {
        if (StringUtils.isEmpty(parentId)) {
            return new ArrayList<>();
        }
        // 子级部门
        List<DepInfoListVO> depInfoTreeList = allDepInfoList.stream()
                .filter(depInfo -> depInfo.getParentId().equals(parentId))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(depInfoTreeList)) {
            return new ArrayList<>();
        }
        // 迭代获取子级部门的下级
        depInfoTreeList.parallelStream().forEach(
                depInfo -> {
                    // 子级的子级部门
                    List<DepInfoListVO> childDepList = buildDepTree(allDepInfoList, depInfo.getId());

                    if (CollectionUtils.isEmpty(childDepList)) {
                        // 没有子部门
                        depInfo.setHasChild(false);
                        depInfo.setChildCount(0);
                        // 没有子部门,子部门员工就是当前部门的员工
                        depInfo.setEmpChildrenCount(depInfo.getEmpDirectCount());
                        depInfo.setEmpChildrenList(depInfo.getEmpDirectList());
                    } else {
                        // 有子部门
                        depInfo.setHasChild(true);
                        depInfo.setChildCount(childDepList.size());
                        depInfo.setDepChildList(childDepList);

                        // 所有子部门的员工
                        List<EmpReduceInfoVO> allChildEmpList = new ArrayList<>();
                        List<String> allChildEmpIdList = new ArrayList<>();
                        childDepList.forEach(
                                childDepInfo -> {
                                    // 子部门及子部门的下级部门所有职工
                                    List<EmpReduceInfoVO> childEmpList = childDepInfo.getEmpChildrenList();
                                    if (!CollectionUtils.isEmpty(childEmpList)) {
                                        childEmpList.forEach(
                                                childEmp -> {
                                                    // 去下重,防止一个员工多个部门计数重复
                                                    if (!allChildEmpIdList.contains(childEmp.getId())) {
                                                        allChildEmpList.add(childEmp);
                                                        allChildEmpIdList.add(childEmp.getId());
                                                    }
                                                }
                                        );
                                    }
                                }
                        );
                        // 将所有子部门员工加到当前部门
                        addAllChildEmpToDep(depInfo, allChildEmpList, allChildEmpIdList);
                    }

                }
        );
        return depInfoTreeList;
    }

    /**
     * 将所有子部门的员工加到当前部门
     *
     * @param depInfoVO         当前部门
     * @param allChildEmpList   所有子部门员工
     * @param allChildEmpIdList 所有子部门员工id
     */
    private void addAllChildEmpToDep(DepInfoListVO depInfoVO, List<EmpReduceInfoVO> allChildEmpList, List<String> allChildEmpIdList) {
        // 当前部门下员工
        List<EmpReduceInfoVO> empList = depInfoVO.getEmpDirectList();
        if (CollectionUtils.isEmpty(empList)) {
            // 部门及子部门职工
            depInfoVO.setEmpChildrenCount(allChildEmpList.size());
            depInfoVO.setEmpChildrenList(allChildEmpList);
        } else {
            // 将当前部门的也直接加到总的里面
            empList.forEach(
                    childEmp -> {
                        // 去下重,防止一个员工多个部门计数重复
                        if (!allChildEmpIdList.contains(childEmp.getId())) {
                            allChildEmpList.add(childEmp);
                            allChildEmpIdList.add(childEmp.getId());
                        }
                    }
            );
            // 部门及子部门职工
            depInfoVO.setEmpChildrenCount(allChildEmpList.size());
            depInfoVO.setEmpChildrenList(allChildEmpList);
        }
    }

    @Override
    public List<DepInfoDO> listAllAndChild(String siteId, String... depIds) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andIn("id", Arrays.asList(depIds))
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true);
        List<DepInfoDO> depInfoList = depInfoDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(depInfoList)) {
            List<String> idList = depInfoList.stream().map(DepInfoDO::getId).collect(Collectors.toList());
            getAllChildList(idList, depInfoList, siteId);
        }
        return depInfoList;
    }

    /**
     * 递归获取所有子分类，单层的
     *
     * @param depList     部门id集合
     * @param depInfoList 所有部门
     * @param siteId      站点id
     */
    private void getAllChildList(List<String> depList, List<DepInfoDO> depInfoList, String siteId) {
        if (CollectionUtils.isEmpty(depList)) {
            return;
        }
        if (depInfoList == null) {
            depInfoList = new ArrayList<>();
        }
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andIn("parentId", depList)
                .andEqualTo("siteId", siteId)
                .andEqualTo("valid", true);
        List<DepInfoDO> list = depInfoDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(list)) {
            depInfoList.addAll(list);
            getAllChildList(list.stream().map(DepInfoDO::getId).collect(Collectors.toList()), depInfoList, siteId);
        }
    }

    @Override
    public DepInfoListVO getCompanyDepEmp(DepAndInfoQuery depAndInfoQuery, TokenUser tokenUser) {
        // 公司层级部门
        DepInfoVO companyDep = selectByCode(depAndInfoQuery.getCompanyId(), tokenUser.getSiteId(), depAndInfoQuery.getCompanyId());
        if (Objects.isNull(companyDep)) {
            return null;
        }
        DepInfoListVO depInfo = companyDep.to(DepInfoListVO.class);
        depAndInfoQuery.setCurrentDepId(companyDep.getId());
        // 公司下级部门及员工
        List<DepInfoListVO> childDep = getDepAndEmpInfo(depAndInfoQuery, tokenUser);
        depInfo.setDepChildList(childDep);

        // 员工查询条件
        EmpReduceQuery empReduceQuery = new EmpReduceQuery(
                depAndInfoQuery.getEmpNameOrPhone(),
                depAndInfoQuery.getOnlyUser(),
                depAndInfoQuery.getIsOnlineOrLeave(),
                true,
                null);

        // 是否只展示当前部门的员工,公司展示全部员工就是展示全部员工
        List<EmpReduceInfoVO> allEmpList = empInfoService.listOnJobByCompanyId(depAndInfoQuery.getCompanyId(), empReduceQuery, tokenUser);

        //去重
        allEmpList = allEmpList.parallelStream().filter(distinctByKey(EmpReduceInfoVO::getId)).peek(empReduceInfoVO -> {
            // 查询员工的额合同信息
            ContractDO contractDO = contractProviderService.selectAllSignedRecordingByCompanyIdAndEmpId(
                    empReduceInfoVO.getCompanyId(), empReduceInfoVO.getId(), tokenUser);
            if (contractDO != null) {
                empReduceInfoVO.setContractType(contractDO.getContractType());
                empReduceInfoVO.setEndDate(contractDO.getEndDate());
                empReduceInfoVO.setDateline(contractDO.getDateline());
                empReduceInfoVO.setSignDate(contractDO.getSignDate());
            }
        }).parallel().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(allEmpList)) {
            depInfo.setAllEmpList(allEmpList);
        }

        // 公司级部门获取无部门员工
        List<EmpReduceInfoVO> noDepEmpList = empInfoService.listNoDepEmp(depAndInfoQuery.getCompanyId(), empReduceQuery, tokenUser);
        depInfo.setNoDepEmpList(noDepEmpList);

        return depInfo;
    }


    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Override
    public List<DepInfoDO> listByName(String name, String companyId, String siteId) {
        // 所有部门
        List<DepInfoDO> depInfoList = listByCompanyId(companyId, siteId);
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new ArrayList<>();
        }
        // 筛选
        depInfoList = depInfoList.stream()
                .filter(depInfo -> depInfo.getName().contains(name)
                        && (StringUtils.isEmpty(depInfo.getCode()) || !depInfo.getCode().equals(companyId)))
                .collect(Collectors.toList());

        return depInfoList;
    }

    @Override
    public Map<String, String> getDepIdAndNameMapByCompany(String companyId, String siteId) {
        // 公司下所有部门
        List<DepInfoDO> depInfoList = listByCompanyId(companyId, siteId);
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new HashMap<>();
        }
        return depInfoList.parallelStream().collect(
                Collectors.toMap(
                        DepInfoDO::getId,
                        DepInfoDO::getName
                )
        );
    }

    @Override
    public List<DepInfoDO> selectByIds(List<String> depInfoIdList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(depInfoIdList)) {
            return new ArrayList<>();
        }
        String siteId = tokenUser.getSiteId();
        return listByIds(siteId, depInfoIdList.toArray(new Object[0]));
    }

    @Override
    public List<String> selectByParentId(List<String> parentIdList, String siteId) {
        List<String> iteratorList = new ArrayList<>(parentIdList);
        for (String parentId : parentIdList) {
            Example example = new Example(DepInfoDO.class);
            example.and()
                    .andEqualTo("parentId", parentId)
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", siteId);
            List<DepInfoDO> contactsDepList = depInfoDAO.selectByExample(example);
            if (CollectionUtils.isEmpty(contactsDepList)) {
                continue;
            }
            List<String> childrenDepIdList =
                    contactsDepList.stream().map(DepInfoDO::getId).collect(Collectors.toList());
            iteratorList.addAll(selectByParentId(childrenDepIdList, siteId));
        }
        return iteratorList;
    }

    @Override
    public List<DepInfoDO> selectDepByParentId(String parentId, String depName, String siteId) {
        Example example = new Example(DepInfoDO.class);
        example.and()
                .andEqualTo("parentId", parentId)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (!StringUtils.isEmpty(depName)) {
            example.and().andLike("name", "%" + depName + "%");
        }
        return depInfoDAO.selectByExample(example);
    }

    @Override
    public List<DepInfoVO> selectDepTree(String companyId, String depName, TokenUser tokenUser) {
        // depInfo 表里面 有一些数据companyId 和 parentId是0 lever是1的 这是站点级别部门
        // 每个站点只有有一条这样的数据 这些数据的code是siteId
        // lever是2的 是公司级别部门(每个用工单位一条数据,也就是说站点下有几个用工单位这样的数据就有几条)
        // 它的 父级Id是站点级别部门  它的code 是用工单位Id(companyId)
        // lever是3的才是正儿八经的部门
        // 查询部门树,顶层是公司及部门
        List<DepInfoVO> depInfoList = depInfoDAO.selectDepTree(companyId, tokenUser.getSiteId());
        // 查询站点级别部门
        DepInfoVO siteDep = selectByCode(tokenUser.getSiteId(), tokenUser.getSiteId(), "0");
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new ArrayList<>();
        }
        // 如果搜索部门  就不返回树了 把符合搜索条件的部门返回一个平铺的list
        EmpDepQuery empDepQuery = new EmpDepQuery();
        empDepQuery.setCompanyId(companyId);
        if (!StringUtils.isEmpty(depName)) {
            return depInfoList.stream()
                    .filter(depInfo -> depInfo.getName().contains(depName))
                    .peek(depInfo -> {
                        // 括号里面的员工数
                        List<String> childrenDepIdList =
                                selectByParentId(Collections.singletonList(depInfo.getId()), tokenUser.getSiteId());
                        depInfo.setEmpDirectCount(empDepService.selectEmpIdListByDepId(
                                childrenDepIdList, empDepQuery, tokenUser.getSiteId()).size());
                    }).collect(Collectors.toList());
        }
        return buildGroupTree(depInfoList, siteDep.getId(), empDepQuery, tokenUser);
    }

    @Override
    public Page<DepInfoVO> depManageByDepId(DepInfoQuery depInfoQuery, TokenUser tokenUser) {
        DepInfoDO depInfoDO = selectById(depInfoQuery.getDepId(), tokenUser);
        List<DepInfoDO> depInfoList = selectDepByParentId(depInfoDO.getId(),
                depInfoQuery.getDepName(), tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(depInfoList)) {
            return new Page<>();
        }
        EmpDepQuery empDepQuery = new EmpDepQuery();
        empDepQuery.setCompanyId(depInfoQuery.getCompanyId());
        List<DepInfoVO> resultList = depInfoList.stream().map(depInfo -> {
            DepInfoVO resultDepInfo = depInfo.to(DepInfoVO.class);
            // 人数
            List<String> childrenDepIdList =
                    selectByParentId(Collections.singletonList(depInfo.getId()), tokenUser.getSiteId());
            resultDepInfo.setEmpDirectCount(empDepService.selectEmpIdListByDepId(
                    childrenDepIdList, empDepQuery, tokenUser.getSiteId()).size());
            // 子部门数量
            resultDepInfo.setChildCount(selectDepByParentId(depInfo.getId(), null, tokenUser.getSiteId()).size());
            return resultDepInfo;
        }).sorted(Comparator.comparing(DepInfoVO::getGmtCreate)).collect(Collectors.toList());
        return PageKit.startPage(resultList, depInfoQuery.getPageNo(), depInfoQuery.getPageSize());
    }

    private List<DepInfoVO> buildGroupTree(List<DepInfoVO> depInfoList, String parentId,
                                           EmpDepQuery empDepQuery, TokenUser tokenUser) {
        List<DepInfoVO> resultList = Lists.newArrayList();
        for (DepInfoVO depInfo : depInfoList) {
            if (depInfo.getParentId().equals(parentId)) {
                DepInfoVO depInfoVO = new DepInfoVO();
                depInfoVO.setId(depInfo.getId());
                depInfoVO.setLevel(depInfo.getLevel());
                depInfoVO.setName(depInfo.getName());
                depInfoVO.setSort(depInfo.getSort());
                depInfoVO.setParentId(depInfo.getParentId());
                depInfoVO.setHasChild(Boolean.TRUE.equals(depInfo.getHasChild()));
                // 先查询这个部门的子部门
                List<String> childrenDepIdList =
                        selectByParentId(Collections.singletonList(depInfo.getId()), tokenUser.getSiteId());
                // 查询部门下的员工数
                depInfoVO.setEmpDirectCount(empDepService.selectEmpIdListByDepId(
                        childrenDepIdList, empDepQuery, tokenUser.getSiteId()).size());
                resultList.add(depInfoVO);
                if (depInfoVO.getHasChild()) {
                    //将父id为此组织的放到子组织列表
                    depInfoVO.setDepChildList(buildGroupTree(depInfoList, depInfoVO.getId(), empDepQuery, tokenUser));
                }
            }
        }
        return resultList;
    }

}




